#include "qdevicedataview.h"

#include "qdataoperator.h"
#include "qdataoperatorpickupdialog.h"


#include "../../libs/core/qsoftcore.h"
#include "../../libs/shared/qprojectcore.h"
#include "../../libs/device/qdevicemanager.h"
#include "../../libs/device/data_sync/qserverdatasync.h"
#include "../../libs/core/stylehelper.h"
#include "../../libs/core/qbtnlineedit.h"

#include <QItemDelegate>
#include <QPainter>
#include <QApplication>
#include <QMouseEvent>
#include <QSpinBox>
#include <QContextMenuEvent>
#include <QMenu>
#include <QDoubleSpinBox>

QWidget* QDeviceDataDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QWidget* ret=NULL;

    if(index.column()==1)
    {
        QString type=index.model()->data(index.model()->index(index.row(),2,index.parent())).toString();
        if(type=="String")
        {
            QBtnLineEdit *l=new QBtnLineEdit(parent);
            ret=l;
        }
        else if(type=="Number")
        {
            QSpinBox *b=new QSpinBox(parent);
            b->setRange(-9999999,9999999);
            ret=b;

        }
        else if(type=="Float")
        {
            QDoubleSpinBox *d=new QDoubleSpinBox(parent);
            d->setRange(-9999999,9999999);
            d->setDecimals(6);
            ret=d;
        }
    }

    if(ret!=NULL)
    {
        ret->setProperty("no-ManhattanStyle",true);
    }

    return ret;
}

void QDeviceDataDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    if(editor->inherits("QBtnLineEdit"))
    {
        QBtnLineEdit *l=(QBtnLineEdit*)editor;
        l->setValue(index.data(Qt::UserRole).toString());
    }
    else
    {
        QItemDelegate::setEditorData(editor,index);
    }
}

void QDeviceDataDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
    QVariant v;

    if(editor->inherits("QBtnLineEdit"))
    {
        QBtnLineEdit *l=(QBtnLineEdit*)editor;
        QString value=l->value();
        model->setData(index,value,Qt::ToolTipRole);
        model->setData(index,value,Qt::UserRole);
        value.replace("\r\n"," ");
        value.replace("\n"," ");
        model->setData(index,value,Qt::EditRole);
        v=l->value();
    }
    else
    {
        QItemDelegate::setModelData(editor,model,index);
        v=model->data(index);
    }

    if(index.column()==1)
    {
        QTreeWidgetItem *item=m_view->itemFromIndex(index);
        QString uuid=m_view->m_item_to_data.value(item);
        tagDataInfo *info=m_view->m_data_sync->get_data(uuid);
        if(info!=NULL)
        {
            m_view->m_device_manager->set_value(m_view->m_device_info.m_uuid,
                                                uuid,v);
        }
    }
}

QDeviceDataView::QDeviceDataView(tagDeviceInfo *info, QWidget *parent):
    QTreeWidget(parent),
    m_device_info(*info)
{
    this->setFrameStyle(QFrame::NoFrame);
    this->setRootIsDecorated(false);
    this->setAlternatingRowColors(true);
    this->setHeaderLabels(QStringList()<<tr("Name")<<tr("Value")<<tr("Type")<<tr("Operator")<<tr("Information"));
    this->setItemDelegate(new QDeviceDataDelegate(this));
    m_device_manager=QSoftCore::get_core()->get_device_manager();
    connect(m_device_manager,SIGNAL(data_refresh(QString)),this,SLOT(data_refresh(QString)));
    connect(m_device_manager,SIGNAL(data_value_refresh(QStringList)),this
            ,SLOT(data_value_refresh(QStringList)));

    m_data_sync=m_device_manager->start_data_sync(info->m_uuid);

}

QDeviceDataView::~QDeviceDataView()
{
    clear();
    m_device_manager->end_data_sync(m_device_info.m_uuid);
}

void QDeviceDataView::data_refresh(const QString &uuid)
{
    if(uuid!=m_device_info.m_uuid)
    {
        return;
    }

    clear();

    QList<tagDataInfo*> datas=m_data_sync->get_datas();

    QTreeWidgetItem *par;
    QTreeWidgetItem *item;

    QIcon icon=StyleHelper::drawIndicatorIcon(this->palette(),this->style());

    foreach(tagDataInfo* data,datas)
    {
        par=m_group_to_item.value(data->m_group);
        if(par==NULL)
        {
            par=new QTreeWidgetItem(this);
            par->setText(0,data->m_group);
            par->setIcon(0,icon);
            m_group_to_item.insert(data->m_group,par);
            for(int i=0;i<this->columnCount();i++)
            {
                par->setData(i,DarkRole,true);
            }
            par->setExpanded(true);
        }

        item=new QTreeWidgetItem(par);
        item->setText(0,data->m_name);
        QString s=data->m_value.toString();
        s.replace("\r\n"," ");
        s.replace("\n"," ");
        item->setText(1,s);
        item->setToolTip(1,data->m_value.toString());
        item->setData(1,Qt::UserRole,data->m_value.toString());
        item->setText(2,data->m_type);
        item->setText(3,tr("None"));
        s=data->m_information;
        s.replace("\r\n"," ");
        s.replace("\n"," ");
        item->setText(4,s);
        item->setToolTip(4,data->m_information);
        if(data->m_lock)
        {
            item->setIcon(0,QIcon(":/images/lock.png"));
        }
        item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable);

        m_item_to_data.insert(item,data->m_uuid);
        m_data_to_item.insert(data->m_uuid,item);
    }

}

void QDeviceDataView::clear()
{
    m_group_to_item.clear();
    m_data_to_item.clear();
    m_item_to_data.clear();

    qDeleteAll(m_data_to_operator.values());
    m_data_to_operator.clear();

    QTreeWidget::clear();
}

void QDeviceDataView::data_value_refresh(const QStringList &list)
{
    foreach(const QString &str,list)
    {
        QTreeWidgetItem *item=m_data_to_item.value(str);
        tagDataInfo *d=m_data_sync->get_data(str);
        if(d!=NULL)
        {
            QString s=d->m_value.toString();
            s.replace("\r\n"," ");
            s.replace("\n"," ");
            item->setText(1,s);
            item->setToolTip(1,d->m_value.toString());
            item->setData(1,Qt::UserRole,d->m_value.toString());
            if(d->m_lock)
            {
                item->setIcon(0,QIcon(":/images/lock.png"));
            }
            else
            {
                item->setIcon(0,QIcon());
            }
        }
    }
}

void QDeviceDataView::drawRow(QPainter *painter, const QStyleOptionViewItem &options, const QModelIndex &index) const
{
    QStyleOptionViewItemV3 opt=options;
    QColor c;
    if(!index.data(DarkRole).toBool())
    {
        c=QColor(BACKGROUND_COLOR);
        opt.palette.setColor(QPalette::AlternateBase,c.lighter(112));
        painter->fillRect(options.rect,c);
    }
    else
    {
        painter->fillRect(options.rect,options.palette.color(QPalette::Dark));
    }
    opt.state &=~ QStyle::State_HasFocus;
    QTreeWidget::drawRow(painter,opt,index);
}

void QDeviceDataView::mousePressEvent(QMouseEvent *event)
{
    QTreeWidgetItem *item=itemAt(event->pos());

    if(m_group_to_item.values().contains(item))
    {
        if(event->x()<20)
        {
            item->setExpanded(!item->isExpanded());
            return;
        }
    }
    QTreeWidget::mousePressEvent(event);
}

void QDeviceDataView::lock()
{
    QTreeWidgetItem* item=currentItem();

    if(item==NULL)
    {
        return;
    }

    QString d=m_item_to_data.value(item);

    tagDataInfo *data=m_data_sync->get_data(d);

    if(data==NULL)
    {
        return;
    }

    if(data->m_lock)
    {
        QAbstractDataOperator* oper=m_data_to_operator.value(data->m_uuid);
        if(oper!=NULL)
        {
            delete oper;
            m_data_to_operator.remove(data->m_uuid);
            item->setText(3,tr("None"));
        }
        QSoftCore::get_core()->get_device_manager()->locked_data(m_device_info.m_uuid,data->m_uuid,false);
    }
    else
    {
        QStringList list;
        list<<tr("Static");

        if(data->m_type=="Number" || data->m_type=="Float")
        {
            list<<tr("Linear");
        }

        list<<tr("Custom");

        QString type;
        if(list.size()>1)
        {
            QDataOperatorPickUpDialog dlg(list);
            dlg.exec();
            type=dlg.get_type();
        }
        else
        {
            type=list.first();
        }
        if(type!="")
        {
            QAbstractDataOperator *oper=NULL;
            if(type==tr("Static"))
            {
                oper=new QStaticDataOPerator(m_device_info.m_uuid,data,m_device_manager);
            }
            else if(type==tr("Linear"))
            {
                if(data->m_type=="Number")
                {
                    oper=new QLinearIntOperator(m_device_info.m_uuid,data,m_device_manager);
                }
                else if(data->m_type=="Float")
                {
                    oper=new QLinearFloatOperator(m_device_info.m_uuid,data,m_device_manager);
                }
            }
            else if(type==tr("Custom"))
            {
                oper=new QCustomOperator(m_device_info.m_uuid,data,m_device_manager);
            }
            if(oper!=NULL)
            {
                if(oper->edit(this))
                {
                    m_data_to_operator.insert(data->m_uuid,oper);
                    QSoftCore::get_core()->get_device_manager()->locked_data(m_device_info.m_uuid,data->m_uuid,true);
                    item->setText(3,type);
                }
                else
                {
                    delete oper;
                }
            }
        }
    }
}

void QDeviceDataView::contextMenuEvent(QContextMenuEvent *e)
{

    QTreeWidgetItem *item=itemAt(e->pos());
    if(item==NULL)
    {
        return;
    }

    QString str=m_item_to_data.value(item);
    tagDataInfo *info=m_data_sync->get_data(str);
    if(info==NULL)
    {
        return;
    }

    QMenu menu;

    menu.addAction(info->m_lock?tr("Unlocked"):tr("Locked"),this,SLOT(lock()));

    menu.exec(e->globalPos());
}
